package org.agony2d.input {
	import flash.display.Stage;
	
	import org.agony2d.core.UpdaterManager;
	import org.agony2d.core.agony_internal;
	import org.agony2d.notify.AEvent;
	import org.agony2d.notify.Notifier;
	import org.agony2d.utils.MathUtil;
	
	use namespace agony_internal
	
	[Event( name = "move",    type = "org.agony2d.notify.AEvent" )]
	
	[Event( name = "release", type = "org.agony2d.notify.AEvent" )]
	
	/** [ Touch ]
	 *  [◆]
	 * 		1.  touchID
	 * 		2.  stageX × stageY
	 * 		3.  prevStageX × prevStageY
	 * 		4.  velocityX × velocityy
	 *  [◆◆]
	 *  	1.  toString
	 *  [★]
	 * 		a.  不可手动实例化...!! ■TouchManager侦听[ NEW_TOUCH ]事件获取...!!
	 */
final public class Touch extends Notifier {
	
	public function Touch() {
		super(null)
		m_maxVelocityX = m_maxVelocityY = 0
	}
	
	final public function get touchID() : int {
		return m_touchID 
	}
	
	final public function get stageX() : Number {
		return m_stageX
	}
	
	final public function get stageY() : Number { 
		return m_stageY
	}
	
	final public function get prevStageX() : Number {
		return m_prevStageX
	}
	
	final public function get prevStageY() : Number { 
		return m_prevStageY 
	}
	
	final public function get velocityX() : Number {
		return m_maxVelocityX 
	}
	
	final public function get velocityY() : Number { 
		return m_maxVelocityY
	}
	
	public function toString() : String {
		return "[touch] - ID [ " + m_touchID + " ]..." + m_stageX + "|" + m_stageY + " / " + m_prevStageX + "|" + m_prevStageY + " / " + m_maxVelocityX + "|" + m_maxVelocityY
	}
	
	agony_internal static const MOVE_FRICTION:Number = .75
	
	agony_internal static var cachedTouchLength:int
	agony_internal static var cachedTouchList:Array = []
//	agony_internal static var g_invalidCount:int = 7
	agony_internal static var g_invalidTime:Number = 0.15
	agony_internal static var g_maxVelocity:int = 30
	agony_internal static var g_stage:Stage
	agony_internal static var g_velocityEnabled:Boolean
	agony_internal static var g_isMoveByFrame:Boolean
	
	agony_internal var m_touchID:int
//	agony_internal var m_currCount:int
	agony_internal var m_invalidTime:Number
	agony_internal var m_moveStateA:Boolean
	agony_internal var m_stageX:Number
	agony_internal var m_stageY:Number
	agony_internal var m_prevStageX:Number
	agony_internal var m_prevStageY:Number
	agony_internal var m_oldAMouseX:Number
	agony_internal var m_oldAMouseY:Number
	agony_internal var m_currMoveX:Number
	agony_internal var m_currMoveY:Number
	agony_internal var m_maxVelocityX:Number
	agony_internal var m_maxVelocityY:Number
	
	
	[Inline]
	final agony_internal function recycle() : void {
		this.removeAllListeners()
		m_moveStateA = false
		m_maxVelocityX = m_maxVelocityY = 0
		cachedTouchList[cachedTouchLength] = this
	}
	
	[Inline]
	final internal function setCoords( stageX:Number, stageY:Number ) : void {
		var tx:Number, ty:Number
		
		if(m_stageX != stageX || m_stageY != stageY) {
			m_stageX = stageX
			m_stageY = stageY
			if (g_isMoveByFrame) {
				m_moveStateA = true
			}
			else {
				this.dispatchDirectEvent(AEvent.MOVE)
				m_prevStageX = m_stageX
				m_prevStageY = m_stageY
			}
			if (g_velocityEnabled) {
				m_oldAMouseX = m_currMoveX
				m_oldAMouseY = m_currMoveY
				m_currMoveX = stageX
				m_currMoveY = stageY
				tx = m_currMoveX - m_oldAMouseX
				ty = m_currMoveY - m_oldAMouseY
				if (MathUtil.adverse(m_maxVelocityX, tx) || Math.abs(tx) > Math.abs(m_maxVelocityX)) {
					m_maxVelocityX = (tx < 0) ? Math.max(tx, -g_maxVelocity) : Math.min(tx, g_maxVelocity)
				}
				if (MathUtil.adverse(m_maxVelocityY, ty) || Math.abs(ty) > Math.abs(m_maxVelocityY)) {
					m_maxVelocityY = (ty < 0) ? Math.max(ty, -g_maxVelocity) : Math.min(ty, g_maxVelocity)
				}
				m_invalidTime = g_invalidTime
			}
		}
	}
	
	[Inline]
	final internal function update() : void {
		// move...
		if (g_isMoveByFrame && m_moveStateA) {
			m_moveStateA = false
			this.dispatchDirectEvent(AEvent.MOVE)
			m_prevStageX = m_stageX
			m_prevStageY = m_stageY
		}
		// velocity...
		if (m_invalidTime > 0) {
			m_invalidTime -= UpdaterManager.g_elapsed * 0.001
			// trace("invalid time : " + m_invalidTime)
			if (m_invalidTime <= 0) {
				m_oldAMouseX = m_currMoveX = m_stageX
				m_oldAMouseY = m_currMoveY = m_stageY
				m_maxVelocityX = m_maxVelocityY = 0
			}
			else {
				m_maxVelocityX *= MOVE_FRICTION
				m_maxVelocityY *= MOVE_FRICTION
			}
		}
	}
	
	[Inline]
	final internal function reset( touchID:int, stageX:Number, stageY:Number ) : Touch {
		m_touchID = touchID
		m_prevStageX = m_stageX = m_currMoveX = stageX
		m_prevStageY = m_stageY = m_currMoveY = stageY
		return this
	}
	
	internal static function NewTouch( touchID:int, stageX:Number, stageY:Number ) : Touch {
		var touch:Touch
		
		touch = (cachedTouchLength > 0 ? cachedTouchLength-- : 0) ? cachedTouchList.pop() : new Touch
		return touch.reset(touchID, stageX, stageY)
	}
}
}